/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pkwserver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.xml.bind.DatatypeConverter;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.core.filterchain.IoFilterChain.Entry;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.ssl.SslFilter;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.omg.CORBA.portable.InputStream;
import pkwserver.commandline.SignRequest;
import pkwserver.singingcert.SignCertificate;
import sun.security.pkcs.PKCS10;
import sun.security.pkcs.PKCS10Attribute;
import sun.security.pkcs.PKCS10Attributes;

/**
 *
 * @author Pawel
 */
public class PKWProtocolHandler extends IoHandlerAdapter {
    private String password = "bskbsk";
    @Override
    public void sessionOpened(IoSession session) {
        session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 20);
        //session.setAttribute(SslFilter.USE_NOTIFICATION);
        System.out.println(session.getReadBytes());
        
       
    }
    
    @Override
    public void exceptionCaught(IoSession session, Throwable cause) {
        cause.printStackTrace();
        session.close(true);
    }
    
    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        
        String s = ((IoBuffer) message).getString(Charset.forName("UTF-8").newDecoder());
        System.out.println(s);
        
        parseMessage(session, s);
        
    }
    
    
     private String bytesToString(byte[] bytes){
        return DatatypeConverter.printBase64Binary(bytes);
    }
    
    private byte[] stringToBytes(String string){
        return DatatypeConverter.parseBase64Binary(string);
    }
    
    
    private Document handleRegistration(Element message) {
        Element session = new Element("session");
        session.setAttribute("name", "registration");
        Document reDoc = new Document(session);
        Element content = message.getChild("PersonalData");
        PersonalData np = new PersonalData();
        System.out.println("PersonalData");
        try {
            MyXmlParser.parseObjcetFromXml(content, np);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(PKWProtocolHandler.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(PKWProtocolHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        Element sigrec = message.getChild("PKCS10");
        int ret =  SignCertificate.dealWithSignReq(sigrec, np, password);
             
      
      //  if(content.getValue().equals("HELLO")) {
            Element msg = new Element("msg");
            Element new_content = new Element("content");
            new_content.addContent("Hello " + np.firstName + " Nie bawie sie tak ");
            Element signed_cert = new Element("signedCertificate");
            Element success  = new Element("result");
            msg.addContent(signed_cert);
            signed_cert.addContent(success);
            Element cert = new Element("Certificate");
            signed_cert.addContent(cert);
            System.out.println("ret == " + ret);
            
            // potrzeb testu to zrobilem
            if(ret == 0){
                byte[] bytes;
                
                try {
                    bytes =  loadSignedCert(np);
                    System.out.println(bytesToString(bytes));
                    success.addContent("OK");
                    System.out.println("Takie byte wczytałem : " + bytesToString(bytes));
                    cert.addContent(bytesToString(bytes));

                } catch (IOException ex) {
                    Logger.getLogger(PKWProtocolHandler.class.getName()).log(Level.SEVERE, null, ex);
                    
                }
            }
            else{
                success.addContent("FAIL");
            }
            
            msg.addContent(new_content);
            session.addContent(msg);
        
         XMLOutputter outputter = new XMLOutputter();
         outputter.setFormat(Format.getPrettyFormat());
        
         try {
                outputter.output(msg, System.out);       
         }
         catch (IOException e) {
         System.err.println(e);
        }
            
        return reDoc;
    }
    
    private Document handleCardGeneration(Element msg) {
        return null;
    }
    
    private Document handleVoting(Element msg) {
        return null;
    }
    
    private void parseMessage(IoSession session, String message) {
        System.out.println("Otrzymałem : message");
        SAXBuilder builder = new SAXBuilder();
        try {
            Document document = builder.build(new StringReader(message));
            Element root = document.getRootElement();
            if(root.getName().equals("session")) {
                String sessionName = root.getAttribute("name").getValue();
                Element msg = root.getChild("msg");
                Document response = null;
                if(sessionName.equalsIgnoreCase("registration")) {
                    response = handleRegistration(msg);
                } else if(sessionName.equalsIgnoreCase("cardgen")) {
                    response = handleCardGeneration(msg);
                } else if(sessionName.equalsIgnoreCase("vote")) {
                    response = handleVoting(msg);
                } else {
                    throw new JDOMException("Wrong session name");
                }

                
                XMLOutputter out = new XMLOutputter();
                out.setFormat(Format.getPrettyFormat());
                
                IoBuffer buf = IoBuffer.allocate(10240, true);
                buf.setAutoExpand(true);
                buf.setAutoShrink(true);
                buf.putString(out.outputString(response), Charset.forName("UTF-8").newEncoder());
                buf.flip();
                WriteFuture wf = session.write(buf);
                
            } else {
                throw new JDOMException("No session given");
            }
        } catch(JDOMException e) {
            System.out.println("Malformed XML");
            System.out.println(e.getMessage());
        } catch(Exception e) { e.printStackTrace(); }
        
        
    }

    private byte[] loadSignedCert(PersonalData np) throws IOException {
        
        StringBuilder sb = new StringBuilder();
        sb.append("certs").append(File.separatorChar).append(np.firstName).append(np.lastName).append(np.Pesel).append(".pem");
        
        return readBytes(new File(sb.toString()));
    }
    
    
    private byte[] readBytes(File file) throws IOException{
    FileInputStream is = new FileInputStream(file);

    // Get the size of the file
    long length = file.length();

    // Create the byte array to hold the data
    byte[] bytes = new byte[(int)length];

    // Read in the bytes
    int offset = 0;
    int numRead = 0;
    while (offset < bytes.length
           && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
        offset += numRead;
    }

    // Ensure all the bytes have been read in
    if (offset < bytes.length) {
        throw new IOException("Could not completely read file "+file.getName());
    }

    // Close the input stream and return bytes
    is.close();
    return bytes;
    }
    
}
